use std::{
    collections::VecDeque,
    sync::{
        mpsc::{Receiver, RecvTimeoutError, Sender},
        Arc, Mutex,
    },
    thread::JoinHandle,
    time::{Duration, Instant},
};

use crate::{
    graphics::graphics_context::{cursor::Cursor, GraphicsContext},
    overlay_window::OverlayWindow,
    utils::{geometry::Position, svg_renderer::render_user_badge_to_png},
    MouseClickData, ScrollDelta, UserEvent,
};

use log::{debug, error};
use winit::event_loop::EventLoopProxy;

/// Platform-specific mouse input implementations and cursor control system.
///
/// This module provides a comprehensive cursor management system that handles both local
/// and remote mouse input, visual cursor representation, and control switching between
/// multiple users. The core component is `CursorController` which coordinates between
/// platform-specific mouse capture and simulation.
///
/// # Core Components
///
/// * **CursorController**: Main API for cursor management and control switching
/// * **MouseObserver**: Platform-specific mouse event capture (background service)
/// * **CursorSimulator**: Platform-specific mouse event injection
///
/// # Control Flow
///
/// The system manages control states between a local sharer and multiple remote controllers:
///
/// * **Sharer Control**: Local user has control, system cursor moves normally, controller cursors are visible
/// * **Controller Control**: A remote controller has control, system cursor follows remote input, sharer virtual cursor is visible
///
/// Control automatically switches based on input activity:
/// * Clicks or scrolling gives control to either the sharer or one controller
/// * Only one entity (sharer or one controller) can have control at a time
///
/// # Multi-Controller Support
///
/// The system supports multiple simultaneous remote controllers, each identified by a unique SID:
/// * Each controller has its own visual cursor representation
/// * Controllers can be individually enabled/disabled for input processing
/// * Controller visibility can be individually controlled (full cursor vs pointer icon)
/// * Control can transfer between any controller or back to the sharer
///
/// # Platform Abstraction
///
/// Each platform implements `MouseObserver` for event capture and `CursorSimulator`
/// for event injection, providing consistent behavior across operating systems.
#[cfg(target_os = "macos")]
#[path = "mouse_macos.rs"]
mod platform;

#[cfg(target_os = "windows")]
#[path = "mouse_windows.rs"]
mod platform;

#[cfg(target_os = "linux")]
#[path = "mouse_linux.rs"]
mod platform;

pub use platform::{CursorSimulator, MouseObserver};

/// Custom identifier used to mark simulated mouse events to prevent feedback loops.
///
/// This constant is embedded in platform-specific mouse events generated by the
/// cursor simulator to distinguish them from real user input. When the mouse
/// observer captures events, it checks for this identifier and ignores events
/// that originated from the simulator itself.
///
/// # Platform Usage
///
/// * **macOS**: Set in `EVENT_SOURCE_USER_DATA` field of CGEvent
/// * **Windows**: Set in `dwExtraInfo` field of MOUSEINPUT structure
/// * **Default**: Not used (no event simulation)
///
/// # Purpose
///
/// Prevents infinite feedback loops where:
/// 1. Simulator generates mouse event with this ID
/// 2. Observer captures the event but sees the ID
/// 3. Observer ignores the event (no feedback to remote)
/// 4. Loop is broken, preventing recursive event generation
pub const CUSTOM_MOUSE_EVENT: i64 = 1234;

/// Maximum number of simultaneous remote controllers supported by the system.
const MAX_CURSORS: u32 = 10;

const SHARER_COLOR: &str = "#7CCF00";

const SHARER_POSITION_UPDATE_INTERVAL: Duration = Duration::from_millis(30);

/// Specific error types for CursorController initialization failures.
///
/// These errors provide detailed information about what component failed during
/// CursorController creation, enabling better error handling and debugging.
#[derive(Debug, thiserror::Error)]
pub enum CursorControllerError {
    /// Failed to create the sharer's cursor graphic.
    ///
    /// This typically indicates a problem loading the native cursor texture
    /// or insufficient graphics resources.
    #[error("Failed to create sharer cursor")]
    SharerCursorCreationFailed,

    /// Failed to create the controller's cursor graphic.
    ///
    /// This typically indicates a problem loading the controller cursor texture
    /// or insufficient graphics resources.
    #[error("Failed to create controller cursor")]
    ControllerCursorCreationFailed,

    #[error("Controller already exists")]
    ControllerAlreadyExists,

    #[error("Failed to render SVG badge")]
    SvgRenderError,

    /// Failed to create the controller's pointer cursor graphic.
    ///
    /// This typically indicates a problem loading the pointer cursor texture
    /// or insufficient graphics resources.
    #[error("Failed to create controller pointer cursor")]
    ControllerPointerCursorCreationFailed,

    /// Failed to initialize platform-specific mouse event capture.
    ///
    /// This indicates the underlying platform API failed to initialize.
    /// Common causes include missing permissions or insufficient privileges.
    #[error("Failed to create mouse observer")]
    MouseObserverCreationFailed,

    #[error("Max controllers reached")]
    MaxControllersReached,
}

/// Platform-agnostic trait for mouse event simulation.
///
/// This trait defines the interface that all platform-specific cursor simulators
/// must implement. It provides methods for simulating mouse movements, clicks,
/// and scroll events at the operating system level.
///
/// ## Platform Implementation Notes:
/// - **macOS**: Uses CGEvent API with Core Graphics event sources
/// - **Windows**: Uses SendInput API with virtual desktop coordinates
/// - **Default**: No-op implementation that logs errors
///
/// All implementations should:
/// 1. Mark simulated events to prevent feedback loops
/// 2. Handle coordinate system differences appropriately
/// 3. Preserve modifier keys and click counts
/// 4. Provide reasonable scroll wheel scaling
pub trait CursorSimulatorFunctions {
    /// Simulates cursor movement to the specified position.
    ///
    /// # Parameters
    /// - `position`: Absolute screen coordinates for cursor placement
    /// - `click_down`: Whether this is a drag operation (mouse button held)
    ///
    /// # Platform Behavior:
    /// - **macOS**: Direct CGEvent posting with pixel coordinates
    /// - **Windows**: SendInput with virtual desktop coordinate mapping
    /// - **Default**: Logs error message only
    fn simulate_cursor_movement(&mut self, position: Position, click_down: bool);

    /// Simulates a mouse click event.
    ///
    /// # Parameters
    /// - `click_data`: Contains button, position, modifiers, and click count
    ///
    /// # Platform Behavior:
    /// - **macOS**: Preserves modifier flags and click count natively
    /// - **Windows**: Converts to INPUT structure with virtual coordinates
    /// - **Default**: Logs error message only
    fn simulate_click(&mut self, click_data: MouseClickData);

    /// Simulates mouse scroll wheel events.
    ///
    /// # Parameters
    /// - `delta`: Scroll delta with x (horizontal) and y (vertical) components
    ///
    /// # Platform Behavior:
    /// - **macOS**: Direct pixel-based scrolling via CGEvent
    /// - **Windows**: Complex translation to WHEEL_DELTA units with rate limiting
    /// - **Default**: Logs error message only
    fn simulate_scroll(&mut self, delta: ScrollDelta);
}

enum CursorWrapperCommands {
    Hide,
    Show(Position),
    Terminate,
}

/// This thread is used for updating the virtual cursor's position,
/// when there isn't any events for 5 seconds, we hide the cursor.
fn cursor_wrapper_thread(cursor: Arc<Mutex<Cursor>>, receiver: Receiver<CursorWrapperCommands>) {
    let timeout = Duration::from_secs(5);
    loop {
        match receiver.recv_timeout(timeout) {
            Ok(command) => match command {
                CursorWrapperCommands::Hide => {
                    let mut cursor = cursor.lock().unwrap();
                    cursor.set_position(-100., -100.);
                }
                CursorWrapperCommands::Show(position) => {
                    let mut cursor = cursor.lock().unwrap();
                    cursor.set_position(position.x, position.y);
                }
                CursorWrapperCommands::Terminate => {
                    break;
                }
            },
            Err(e) => match e {
                RecvTimeoutError::Timeout => {
                    let mut cursor = cursor.lock().unwrap();
                    cursor.set_position(-100., -100.);
                }
                _ => {
                    log::error!("cursor_wrapper_thread: error receiving command: {e:?}");
                    break;
                }
            },
        }
    }
}

struct CursorWrapper {
    cursor: Arc<Mutex<Cursor>>,
    /// Cursor's position in global coordinates, this is used when simulating events
    global_position: Position,
    /// Cursor's position in local coordinates, this is used for rendering
    local_position: Position,
    /// Handle for the thread that updates the cursor's position
    hide_handle: Option<JoinHandle<()>>,
    command_sender: Sender<CursorWrapperCommands>,
}

impl CursorWrapper {
    fn new(cursor: Cursor) -> Self {
        let cursor = Arc::new(Mutex::new(cursor));
        let (tx, rx) = std::sync::mpsc::channel();
        Self {
            cursor: cursor.clone(),
            global_position: Position::default(),
            local_position: Position::default(),
            hide_handle: Some(std::thread::spawn(move || {
                cursor_wrapper_thread(cursor, rx)
            })),
            command_sender: tx,
        }
    }

    fn set_position(&mut self, global_position: Position, local_position: Position, show: bool) {
        log::debug!(
            "set_position: global_position: {global_position:?} local_position: {local_position:?}"
        );
        self.global_position = global_position;
        self.local_position = local_position;
        if show {
            if let Err(e) = self
                .command_sender
                .send(CursorWrapperCommands::Show(local_position))
            {
                log::error!("cursor_wrapper_thread: error sending show command: {e:?}");
            }
        }
    }

    fn hide(&mut self) {
        if let Err(e) = self.command_sender.send(CursorWrapperCommands::Hide) {
            log::error!("cursor_wrapper_thread: error sending hide command: {e:?}");
        }
    }

    fn show(&mut self) {
        if let Err(e) = self
            .command_sender
            .send(CursorWrapperCommands::Show(self.local_position))
        {
            log::error!("cursor_wrapper_thread: error sending show command: {e:?}");
        }
    }

    fn draw(&self, render_pass: &mut wgpu::RenderPass, gfx: &GraphicsContext) {
        let cursor = self.cursor.lock().unwrap();
        cursor.update_transform_buffer(gfx);
        cursor.draw(render_pass, gfx);
    }
}

impl Drop for CursorWrapper {
    fn drop(&mut self) {
        if let Some(handle) = self.hide_handle.take() {
            let res = self.command_sender.send(CursorWrapperCommands::Terminate);
            if let Err(e) = res {
                log::error!("cursor_wrapper_thread: error sending terminate command: {e:?}");
            } else {
                let _ = handle.join();
            }
        }
    }
}

struct ControllerCursor {
    /// Cursor that is shown when the controller is allowed to take control
    control_cursor: CursorWrapper,
    /// Cursor that is shown when the controller is not allowed to take control
    pointer_cursor: CursorWrapper,
    /*
     * This is used to record when the controller
     * clicked down. Then for each mouse move we
     * send LeftMouseDragged instead of MouseMoved.
     */
    clicked: bool,
    enabled: bool,
    pointer_enabled: bool,
    has_control: bool,
    visible_name: String,
    sid: String,
    color: &'static str,
}

impl ControllerCursor {
    fn new(
        control_cursor: CursorWrapper,
        pointer_cursor: CursorWrapper,
        sid: String,
        visible_name: String,
        enabled: bool,
        color: &'static str,
    ) -> Self {
        Self {
            control_cursor,
            pointer_cursor,
            clicked: false,
            enabled,
            pointer_enabled: false,
            has_control: false,
            visible_name,
            sid,
            color,
        }
    }

    fn set_position(&mut self, global_position: Position, local_position: Position) {
        log::debug!(
            "controller_cursor: set_position: global_position: {:?} local_position: {:?} has_control: {} enabled: {}",
            global_position,
            local_position,
            self.has_control,
            self.enabled_control_cursor()
        );
        self.control_cursor.set_position(
            global_position,
            local_position,
            !self.has_control && self.enabled_control_cursor(),
        );
        self.pointer_cursor.set_position(
            global_position,
            local_position,
            !self.has_control && !self.enabled_control_cursor(),
        );
    }

    fn show(&mut self) {
        self.has_control = false;
        if self.enabled_control_cursor() {
            self.control_cursor.show();
        } else {
            self.pointer_cursor.show();
        }
    }

    fn hide(&mut self) {
        if self.enabled_control_cursor() {
            self.has_control = true;
            self.control_cursor.hide();
        } else {
            self.pointer_cursor.hide();
        }
    }

    fn enabled_control_cursor(&self) -> bool {
        self.enabled && !self.pointer_enabled
    }

    fn enabled(&self) -> bool {
        self.enabled
    }

    fn set_enabled(&mut self, enabled: bool) {
        self.enabled = enabled;

        if enabled && !self.pointer_enabled {
            self.control_cursor.show();
            self.pointer_cursor.hide();
        } else {
            self.control_cursor.hide();
            self.pointer_cursor.show();
        }
    }

    fn clicked(&mut self) -> bool {
        self.clicked
    }

    fn set_clicked(&mut self, clicked: bool) {
        self.clicked = clicked;
    }

    fn global_position(&self) -> Position {
        self.control_cursor.global_position
    }

    fn draw(&self, render_pass: &mut wgpu::RenderPass, gfx: &GraphicsContext) {
        if self.has_control {
            return;
        }

        if self.enabled && !self.pointer_enabled {
            self.control_cursor.draw(render_pass, gfx);
        } else {
            self.pointer_cursor.draw(render_pass, gfx);
        }
    }

    fn has_control(&self) -> bool {
        self.has_control
    }

    fn set_pointer_enabled(&mut self, pointer_enabled: bool) {
        self.pointer_enabled = pointer_enabled;

        if pointer_enabled {
            self.pointer_cursor.show();
            self.control_cursor.hide();
        } else if self.enabled {
            self.pointer_cursor.hide();
            self.control_cursor.show();
        }
    }

    fn pointer_enabled(&self) -> bool {
        self.pointer_enabled
    }
}

pub struct SharerCursor {
    cursor: CursorWrapper,
    has_control: bool,
    event_loop_proxy: EventLoopProxy<UserEvent>,
    overlay_window: Arc<OverlayWindow>,
    /// We are using this to take control back when the sharer clicks/scrolls
    controllers_cursors: Arc<Mutex<Vec<ControllerCursor>>>,
    cursor_simulator: Arc<Mutex<CursorSimulator>>,
    last_event_position: Position,
    last_event_position_time: Instant,
}

impl SharerCursor {
    fn new(
        cursor: CursorWrapper,
        event_loop_proxy: EventLoopProxy<UserEvent>,
        overlay_window: Arc<OverlayWindow>,
        cursor_simulator: Arc<Mutex<CursorSimulator>>,
        controllers_cursors: Arc<Mutex<Vec<ControllerCursor>>>,
    ) -> Self {
        Self {
            cursor,
            has_control: true,
            event_loop_proxy,
            overlay_window,
            controllers_cursors,
            cursor_simulator,
            last_event_position: Position::default(),
            last_event_position_time: Instant::now(),
        }
    }

    fn set_position(&mut self, global_position: Position) {
        log::debug!("sharer_cursor: set_position: global_position: {global_position:?}");

        let local_position = self
            .overlay_window
            .local_percentage_from_global(global_position.x, global_position.y);
        let display_percentage = self
            .overlay_window
            .global_percentage_from_global(global_position.x, global_position.y);

        self.cursor
            .set_position(global_position, local_position, !self.has_control);

        if self.last_event_position_time.elapsed() > SHARER_POSITION_UPDATE_INTERVAL {
            let res = self.event_loop_proxy.send_event(UserEvent::SharerPosition(
                display_percentage.x,
                display_percentage.y,
            ));
            if let Err(e) = res {
                error!("sharer_cursor: set_position: error sending sharer position: {e:?}");
            }
            self.last_event_position_time = Instant::now();
        }
    }

    fn click(&mut self) {
        log::debug!("sharer_cursor: click: has_control: {}", self.has_control);

        if self.has_control {
            return;
        }

        self.hide();
        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            if controller.has_control() {
                controller.show();
            }
        }

        /*
         * When the sharer takes back control with with a click, we need to move
         * the system cursor to the position of the click, because the system cursor
         * was were the controlling controller was.
         */
        let mut cursor_simulator = self.cursor_simulator.lock().unwrap();
        let global_position = self.global_position();
        cursor_simulator.simulate_click(MouseClickData {
            x: global_position.x as f32,
            y: global_position.y as f32,
            button: 0,
            clicks: 1.,
            down: true,
            shift: false,
            alt: false,
            ctrl: false,
            meta: false,
        });
    }

    fn scroll(&mut self) {
        log::debug!("sharer_cursor: scroll: has_control: {}", self.has_control);

        if self.has_control {
            return;
        }

        self.hide();
        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            if controller.has_control() {
                controller.show();
            }
        }
    }

    fn has_control(&self) -> bool {
        self.has_control
    }

    fn global_position(&self) -> Position {
        self.cursor.global_position
    }

    fn draw(&self, render_pass: &mut wgpu::RenderPass, gfx: &GraphicsContext) {
        if !self.has_control {
            self.cursor.draw(render_pass, gfx);
        }
    }

    fn show(&mut self) {
        self.has_control = false;
        self.cursor.show();
    }

    fn hide(&mut self) {
        self.has_control = true;
        self.cursor.hide();

        let mut cursor_simulator = self.cursor_simulator.lock().unwrap();
        let global_position = self.global_position();
        cursor_simulator.simulate_cursor_movement(global_position, false);

        let res = self
            .event_loop_proxy
            .send_event(UserEvent::ParticipantInControl("sharer".to_string()));
        if let Err(e) = res {
            error!("sharer_cursor: click: error sending participant in control: {e:?}");
        }
    }

    #[allow(dead_code)]
    fn set_last_event_position(&mut self, position: Position) {
        self.last_event_position = position;
    }

    #[allow(dead_code)]
    fn get_last_event_position(&self) -> Position {
        self.last_event_position
    }
}

enum RedrawThreadCommands {
    Stop,
}

/*
 * Instead of sending a redraw request after each mouse event, control
 * the redraws to happen in 60fps.
 */
fn redraw_thread(
    event_loop_proxy: EventLoopProxy<UserEvent>,
    receiver: Receiver<RedrawThreadCommands>,
) {
    loop {
        match receiver.recv_timeout(std::time::Duration::from_millis(12)) {
            Ok(command) => match command {
                RedrawThreadCommands::Stop => break,
            },
            Err(e) => match e {
                RecvTimeoutError::Timeout => {
                    if let Err(e) = event_loop_proxy.send_event(UserEvent::RequestRedraw) {
                        log::error!("redraw_thread: error sending redraw event: {e:?}");
                    }
                }
                _ => {
                    log::error!("redraw_thread: error receiving command: {e:?}");
                    break;
                }
            },
        }
    }
}

struct RemoteControl {
    /// Cursor that is shown when the sharer looses control
    sharer_cursor: Arc<Mutex<SharerCursor>>,
    /// Object that is used to simulate mouse events
    cursor_simulator: Arc<Mutex<CursorSimulator>>,
    /// Platform-specific mouse event observer.
    ///
    /// Captures system-wide mouse events and updates internal state via callbacks.
    /// Lifetime parameter ensures observer doesn't outlive controller.
    _mouse_observer: MouseObserver,
}

/// Main cursor controller that manages both local and remote cursor interactions.
///
/// It manages the visual representation of multiple remote controller cursors and
/// handles control switching between the local sharer and remote controllers.
///
/// ## Architecture:
/// - **MouseObserver**: Platform-specific event capture
/// - **CursorSimulator**: Platform-specific event injection
/// - **Multi-Controller Support**: Manages up to MAX_CURSORS simultaneous controllers
///
/// ## Controller Management:
/// - Controllers are identified by unique session IDs (SIDs)
/// - Each controller has independent enable/disable and visibility states
/// - Controllers can be dynamically added and removed during sessions
/// - Visual cursor representation includes user badges with distinct colors
///
/// ## Error Handling:
/// Constructor returns `CursorControllerError` with specific failure reasons:
/// - `SharerCursorCreationFailed`: Graphics resources unavailable
/// - `ControllerCursorCreationFailed`: Controller cursor texture failed
/// - `ControllerPointerCursorCreationFailed`: Pointer cursor texture failed
/// - `MouseObserverCreationFailed`: Platform mouse capture initialization failed
/// - `ControllerAlreadyExists`: Attempted to add controller with existing SID
/// - `MaxControllersReached`: Exceeded maximum number of controllers
pub struct CursorController {
    /// Objects that are used for remote control. When accessibility permission is not granted,
    /// this is None.
    remote_control: Option<RemoteControl>,
    /// Cursors for the remote controllers
    controllers_cursors: Arc<Mutex<Vec<ControllerCursor>>>,
    /// Controllers' cursors enabled by the shared
    controllers_cursors_enabled: bool,
    /// Object that is used to translate coordinates between local and global
    overlay_window: Arc<OverlayWindow>,
    /// Thread that is used to control the redraws
    redraw_thread: Option<JoinHandle<()>>,
    /// Sender for the redraw thread
    redraw_thread_sender: Sender<RedrawThreadCommands>,
    /// Event loop proxy for sending events
    event_loop_proxy: EventLoopProxy<UserEvent>,
    /// Available colors for new controllers
    available_colors: VecDeque<&'static str>,
}

impl CursorController {
    /// Creates a new cursor controller with platform-specific mouse capture and simulation.
    ///
    /// This function initializes all necessary components for cursor management:
    /// - Creates visual cursor representation for the local sharer
    /// - Sets up platform-specific mouse event capture
    /// - Initializes cursor simulation capabilities
    /// - Establishes communication with the graphics and overlay systems
    /// - Prepares infrastructure for managing multiple remote controllers
    ///
    /// Note: Remote controllers are added separately using `add_controller()` method.
    ///
    /// # Parameters
    ///
    /// * `gfx` - Graphics context for creating cursor textures and render resources
    /// * `overlay_window` - Shared overlay window for coordinate transformations
    /// * `event_loop_proxy` - Event loop proxy for sending cursor position updates
    ///
    /// # Returns
    ///
    /// * `Ok(CursorController)` - Successfully initialized controller
    /// * `Err(CursorControllerError)` - Specific failure reason (see error variants)
    pub fn new(
        gfx: &mut GraphicsContext,
        overlay_window: Arc<OverlayWindow>,
        event_loop_proxy: EventLoopProxy<UserEvent>,
        accessibility_permission: bool,
    ) -> Result<Self, CursorControllerError> {
        let controllers_cursors = Arc::new(Mutex::new(vec![]));

        let event_loop_proxy_clone = event_loop_proxy.clone();

        let remote_control = if accessibility_permission {
            let scale_factor = overlay_window.get_display_scale();
            let color = SHARER_COLOR;
            let svg_badge = render_user_badge_to_png(color, "Me ", false)
                .map_err(|_| CursorControllerError::SvgRenderError)?;
            let sharer_cursor = match gfx.create_cursor(&svg_badge, scale_factor) {
                Ok(cursor) => cursor,
                Err(_) => return Err(CursorControllerError::SharerCursorCreationFailed),
            };

            let cursor_simulator = Arc::new(Mutex::new(CursorSimulator::new()));
            let sharer_cursor = Arc::new(Mutex::new(SharerCursor::new(
                CursorWrapper::new(sharer_cursor),
                event_loop_proxy.clone(),
                overlay_window.clone(),
                cursor_simulator.clone(),
                controllers_cursors.clone(),
            )));

            let mouse_observer = MouseObserver::new(sharer_cursor.clone());
            if mouse_observer.is_err() {
                error!("CursorController::new: error creating mouse observer");
                return Err(CursorControllerError::MouseObserverCreationFailed);
            }
            let mouse_observer = mouse_observer.unwrap();

            Some(RemoteControl {
                sharer_cursor,
                cursor_simulator,
                _mouse_observer: mouse_observer,
            })
        } else {
            None
        };

        let (sender, receiver) = std::sync::mpsc::channel();
        let available = VecDeque::from([
            "#615FFF", "#009689", "#C800DE", "#00A6F4", "#FFB900", "#ED0040", "#E49500", "#B80088",
            "#FF5BFF", "#00D091",
        ]);

        Ok(Self {
            remote_control,
            controllers_cursors,
            controllers_cursors_enabled: accessibility_permission,
            overlay_window,
            redraw_thread: Some(std::thread::spawn(move || {
                redraw_thread(event_loop_proxy_clone, receiver);
            })),
            redraw_thread_sender: sender,
            event_loop_proxy,
            available_colors: available,
        })
    }

    /// Adds a new remote controller to the cursor management system.
    ///
    /// This function creates visual cursor representations for a new remote controller
    /// and adds it to the active controller list. Each controller gets a unique color
    /// badge and can be independently controlled.
    ///
    /// # Parameters
    ///
    /// * `gfx` - Graphics context for creating cursor textures
    /// * `sid` - Unique session ID for the controller (must not already exist)
    /// * `name` - Display name for the controller (used in visual badge)
    ///
    /// # Returns
    ///
    /// * `Ok(())` - Controller successfully added
    /// * `Err(CursorControllerError)` - Addition failed for specific reason:
    ///   - `ControllerAlreadyExists`: SID already in use
    ///   - `MaxControllersReached`: Maximum controllers exceeded
    ///   - `ControllerCursorCreationFailed`: Graphics resource creation failed
    ///   - `ControllerPointerCursorCreationFailed`: Pointer cursor creation failed
    ///   - `SvgRenderError`: Badge rendering failed
    ///
    /// # Name Generation
    ///
    /// If multiple controllers have the same name, the system automatically generates
    /// unique visible names (e.g., "John" → "John", "John S", "John Smith", "John Smith2").
    pub fn add_controller(
        &mut self,
        gfx: &mut GraphicsContext,
        sid: String,
        name: String,
    ) -> Result<(), CursorControllerError> {
        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        log::info!(
            "add_controller: sid: {} controllers_cursors: {}",
            sid,
            controllers_cursors.len()
        );
        for controller in controllers_cursors.iter() {
            if controller.sid == sid {
                return Err(CursorControllerError::ControllerAlreadyExists);
            }
        }

        if controllers_cursors.len() + 1 > MAX_CURSORS as usize {
            return Err(CursorControllerError::MaxControllersReached);
        }

        let color = match self.available_colors.pop_front() {
            Some(color) => color,
            None => return Err(CursorControllerError::MaxControllersReached),
        };
        let used_names: Vec<String> = controllers_cursors
            .iter()
            .map(|c| c.visible_name.clone())
            .collect();
        let visible_name = generate_unique_visible_name(&name, &used_names);
        let scale_factor = self.overlay_window.get_display_scale();
        let svg_badge = render_user_badge_to_png(color, &visible_name, false)
            .map_err(|_| CursorControllerError::SvgRenderError)?;

        let controller_cursor = match gfx.create_cursor(&svg_badge, scale_factor) {
            Ok(cursor) => cursor,
            Err(_) => return Err(CursorControllerError::ControllerCursorCreationFailed),
        };
        let svg_badge_pointer = render_user_badge_to_png(color, &visible_name, true)
            .map_err(|_| CursorControllerError::SvgRenderError)?;
        let controller_pointer_cursor = match gfx.create_cursor(&svg_badge_pointer, scale_factor) {
            Ok(cursor) => cursor,
            Err(_) => return Err(CursorControllerError::ControllerPointerCursorCreationFailed),
        };

        controllers_cursors.push(ControllerCursor::new(
            CursorWrapper::new(controller_cursor),
            CursorWrapper::new(controller_pointer_cursor),
            sid,
            visible_name,
            self.controllers_cursors_enabled,
            color,
        ));
        Ok(())
    }

    /// Removes a remote controller from the cursor management system.
    ///
    /// This function removes the specified controller from the active controller list
    /// and cleans up its visual resources. If the removed controller currently has
    /// control, control will remain with the system until another input event occurs.
    ///
    /// # Parameters
    ///
    /// * `sid` - Session ID of the controller to remove
    ///
    /// # Behavior
    ///
    /// * If the controller exists, it is immediately removed from the list
    /// * If the controller doesn't exist, the operation is silently ignored
    /// * Visual cursor resources are automatically cleaned up
    /// * Control state is preserved until next input event
    pub fn remove_controller(&mut self, sid: &str) {
        log::info!("remove_controller: {sid}");
        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();

        if let Some(pos) = controllers_cursors
            .iter()
            .position(|controller| controller.sid == sid)
        {
            // take ownership so we can recover color
            let controller = controllers_cursors.remove(pos);
            self.available_colors.push_back(controller.color);
        } else {
            // no-op if not present
            log::info!("remove_controller: controller with sid {} not found", sid);
        }
    }

    /// Handles controller cursor movement from remote input.
    ///
    /// This function processes cursor movement commands from a specific remote controller,
    /// updating both the visual cursor position and potentially moving the system
    /// cursor if that controller has control.
    ///
    /// # Parameters
    ///
    /// * `x` - Local window coordinates as percentage (0.0-1.0 range) for horizontal position
    /// * `y` - Local window coordinates as percentage (0.0-1.0 range) for vertical position
    /// * `sid` - Session ID identifying which controller is moving
    pub fn cursor_move_controller(&mut self, x: f64, y: f64, sid: &str) {
        debug!("cursor_move_controller: x: {x} y: {y}");

        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            if controller.sid != sid {
                continue;
            }

            let local_position = self.overlay_window.translate_location(x, y);
            let global_position = self.overlay_window.translate_to_global(x, y);

            controller.set_position(global_position, local_position);
            if controller.has_control() && self.remote_control.is_some() {
                let mut cursor_simulator = self
                    .remote_control
                    .as_ref()
                    .unwrap()
                    .cursor_simulator
                    .lock()
                    .unwrap();
                cursor_simulator.simulate_cursor_movement(global_position, controller.clicked());
            }
            break;
        }
    }

    /// Handles mouse click events from a specific remote controller.
    ///
    /// This function processes mouse button press/release events from a specific remote controller,
    /// potentially taking control from the local sharer or other controllers and simulating
    /// the click on the local system.
    ///
    /// # Parameters
    ///
    /// * `click_data` - Complete mouse click information including:
    /// * `sid` - Session ID identifying which controller is clicking
    pub fn mouse_click_controller(&mut self, mut click_data: MouseClickData, sid: &str) {
        debug!("mouse_click_controller: {click_data:?}");
        if self.remote_control.is_none() {
            log::warn!("mouse_click_controller: remote control is none");
            return;
        }

        let mut control_changed = false;
        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            if controller.sid != sid {
                continue;
            }

            if !controller.enabled() || controller.pointer_enabled() {
                log::info!("mouse_click_controller: controller is disabled.");
                if click_data.down && controller.pointer_enabled() {
                    if let Err(e) =
                        self.event_loop_proxy
                            .send_event(UserEvent::EnableClickAnimation(Position {
                                x: click_data.x as f64,
                                y: click_data.y as f64,
                            }))
                    {
                        error!(
                            "mouse_click_controller: error sending enable click animation: {e:?}"
                        );
                    }
                }
                break;
            }

            let global_position = self
                .overlay_window
                .translate_to_global(click_data.x as f64, click_data.y as f64);
            click_data.x = global_position.x as f32;
            click_data.y = global_position.y as f32;

            /* Take control. */
            if click_data.down && !controller.has_control() {
                debug!("mouse_click_controller: controller {sid} takes control.");
                controller.hide();
                control_changed = true;
            }

            if click_data.clicks <= 1. {
                controller.set_clicked(click_data.down);
            }

            let mut cursor_simulator = self
                .remote_control
                .as_ref()
                .unwrap()
                .cursor_simulator
                .lock()
                .unwrap();
            /* Take the cursor to the controller's position. */
            cursor_simulator.simulate_cursor_movement(global_position, false);
            cursor_simulator.simulate_click(click_data);

            break;
        }

        /* Remove control from the previous controller. */
        if control_changed {
            for controller in controllers_cursors.iter_mut() {
                if controller.has_control() && controller.sid != sid {
                    controller.show();
                }
            }
        }

        /* Show the sharer cursor. */
        let mut sharer_cursor = self
            .remote_control
            .as_ref()
            .unwrap()
            .sharer_cursor
            .lock()
            .unwrap();
        if sharer_cursor.has_control() && control_changed {
            sharer_cursor.show();
        }

        /* Notify controllers who has control. */
        if control_changed {
            let res = self
                .event_loop_proxy
                .send_event(UserEvent::ParticipantInControl(sid.to_string()));
            if let Err(e) = res {
                error!("mouse_click_controller: error sending participant in control: {e:?}");
            }
        }
    }

    /// Handles scroll wheel events from a specific remote controller.
    ///
    /// This function processes scroll wheel input from a specific remote controller,
    /// potentially taking control from the local sharer or other controllers and
    /// simulating the scroll action on the local system.
    ///
    /// # Parameters
    ///
    /// * `delta` - Scroll wheel movement with:
    /// * `sid` - Session ID identifying which controller is scrolling
    pub fn scroll_controller(&mut self, delta: ScrollDelta, sid: &str) {
        debug!("scroll_controller: {delta:?}");

        if self.remote_control.is_none() {
            log::warn!("scroll_controller: remote control is none");
            return;
        }

        let mut control_changed = false;
        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            if controller.sid != sid {
                continue;
            }

            if !controller.enabled() || controller.pointer_enabled() {
                log::info!("scroll_controller: controller is disabled.");
                break;
            }

            if !controller.has_control() {
                control_changed = true;
                controller.hide();
            }

            let mut cursor_simulator = self
                .remote_control
                .as_ref()
                .unwrap()
                .cursor_simulator
                .lock()
                .unwrap();
            cursor_simulator.simulate_cursor_movement(controller.global_position(), false);
            cursor_simulator.simulate_scroll(delta);

            break;
        }

        /* Remove control from the previous controller. */
        if control_changed {
            for controller in controllers_cursors.iter_mut() {
                if controller.has_control() && controller.sid != sid {
                    controller.show();
                }
            }
        }

        /* Show the sharer cursor. */
        let mut sharer_cursor = self
            .remote_control
            .as_ref()
            .unwrap()
            .sharer_cursor
            .lock()
            .unwrap();
        if sharer_cursor.has_control() && control_changed {
            sharer_cursor.show();
        }

        /* Notify controllers who has control. */
        if control_changed {
            let res = self
                .event_loop_proxy
                .send_event(UserEvent::ParticipantInControl(sid.to_string()));
            if let Err(e) = res {
                error!("scroll_controller: error sending participant in control: {e:?}");
            }
        }
    }

    /// Enables or disables input processing for all controllers.
    ///
    /// This function controls whether remote controllers can interact with the
    /// local system. When disabled, all controller input events are ignored and no
    /// control transfer occurs from any controller.
    ///
    /// # Parameters
    ///
    /// * `enabled` - Whether to enable (true) or disable (false) input for all controllers
    pub fn set_controllers_enabled(&mut self, enabled: bool) {
        log::info!("set_controllers_enabled: {enabled}");
        if self.remote_control.is_none() {
            log::warn!("set_controllers_enabled: remote control is none");
            return;
        }

        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        self.controllers_cursors_enabled = enabled;
        for controller in controllers_cursors.iter_mut() {
            controller.set_enabled(enabled);

            if controller.has_control() {
                controller.show();
                let mut sharer_cursor = self
                    .remote_control
                    .as_ref()
                    .unwrap()
                    .sharer_cursor
                    .lock()
                    .unwrap();
                sharer_cursor.hide();
            }
        }
    }

    /// Makes a specific controller disabled, this is triggered by an event from the
    /// controller, while set_controllers_enabled is used to disable all controllers
    /// and is triggered by the sharer.
    ///
    /// # Parameters
    ///
    /// * `enabled` - Whether to show full cursor (true) or minimal pointer (false)
    /// * `sid` - Session ID identifying which controller to modify
    pub fn set_controller_pointer_enabled(&mut self, enabled: bool, sid: &str) {
        log::info!("set_controller_pointer_enabled: {enabled} {sid}");

        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            if controller.sid != sid {
                continue;
            }

            if controller.has_control() {
                log::info!("set_controller_pointer_enabled: controller {sid} has control, give control back to sharer.");
                controller.show();
                let mut sharer_cursor = self
                    .remote_control
                    .as_ref()
                    .unwrap()
                    .sharer_cursor
                    .lock()
                    .unwrap();
                sharer_cursor.hide();
            }

            controller.set_pointer_enabled(enabled);
            break;
        }
    }

    /// Renders all appropriate cursors to the overlay during the graphics draw cycle.
    ///
    /// This function is called during each frame rendering to draw the current cursor
    /// states to the overlay window. It automatically selects which cursors to display
    /// based on the current control state and individual controller configurations.
    ///
    /// # Parameters
    ///
    /// * `render_pass` - Active wgpu render pass for drawing operations
    /// * `gfx` - Graphics context containing shaders, buffers, and render state
    ///
    pub fn draw(&self, render_pass: &mut wgpu::RenderPass, gfx: &GraphicsContext) {
        log::trace!("draw cursors");
        if self.remote_control.is_some() {
            let sharer_cursor = self
                .remote_control
                .as_ref()
                .unwrap()
                .sharer_cursor
                .lock()
                .unwrap();
            sharer_cursor.draw(render_pass, gfx);
        }

        let mut controllers_cursors = self.controllers_cursors.lock().unwrap();
        for controller in controllers_cursors.iter_mut() {
            controller.draw(render_pass, gfx);
        }
    }
}

impl Drop for CursorController {
    fn drop(&mut self) {
        if let Some(handle) = self.redraw_thread.take() {
            let _ = self.redraw_thread_sender.send(RedrawThreadCommands::Stop);
            let _ = handle.join();
        }
    }
}

fn generate_unique_visible_name(name: &str, used_names: &[String]) -> String {
    let parts: Vec<&str> = name.split_whitespace().collect();
    let first_name = parts.first().unwrap_or(&name);

    // Try progressively longer candidates
    let candidates = if parts.len() > 1 {
        let last_name = parts[1];
        let mut candidates = vec![first_name.to_string()];

        // Add candidates with increasing characters from last name
        for i in 1..=last_name.chars().count() {
            let partial_last_name: String = last_name.chars().take(i).collect();
            candidates.push(format!("{first_name} {partial_last_name}"));
        }
        candidates
    } else {
        vec![first_name.to_string()]
    };

    // Find first unused candidate
    for candidate in candidates.iter() {
        if !used_names.contains(candidate) {
            return candidate.clone();
        }
    }

    // Fall back to numbering
    let base = candidates.last().unwrap().clone();
    for num in 2.. {
        let candidate = format!("{base}{num}");
        if !used_names.contains(&candidate) {
            return candidate;
        }
    }

    unreachable!()
}
